#include "GlobalFunc.h"
#include <cstdint>
#include <iterator>


using namespace std;


#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32

#define MASK8(i) static_cast<uint32_t>(static_cast<uint8_t>(i))
#define MASK16(i) static_cast<uint32_t>(static_cast<uint16_t>(i))
#define CAST8(i) static_cast<char>(i)
#define CAST16(i) static_cast<wchar_t>(i)
#define CHECK(exp) if (!(exp)) return false;

// Internal function. Make sure that (in != end) before calling.
static bool WidenChar(string::const_iterator & in, string::const_iterator end, back_insert_iterator<wstring> & out)
{
	uint32_t first = MASK8(*in++);
	uint32_t cont;
	uint32_t ret;
	if ((first & 0x80) == 0)
	{
		CHECK(first != 0x00); // NULL
		*out++ = CAST16(first);
		return true;
	}
	CHECK((first & 0x40) != 0);
	CHECK(in != end);
	if ((first & 0x20) == 0)
	{
		ret = (first & 0x1f) << 6;
		cont = MASK8(*in);
		CHECK(((cont ^ 0x80) & -0x40) == 0);
		ret |= cont & 0x3f;
		++in;
		CHECK((ret & -0x0080) != 0);
		*out++ = CAST16(ret);
		return true;
	}
	if ((first & 0x10) == 0)
	{
		ret = (first & 0x0f) << 12;
		cont = MASK8(*in);
		CHECK(((cont ^ 0x80) & -0x40) == 0);
		ret |= (cont & 0x3f) << 6;
		CHECK(++in != end);
		cont = MASK8(*in);
		CHECK(((cont ^ 0x80) & -0x40) == 0);
		ret |= cont & 0x3f;
		++in;
		CHECK((ret & -0x0800) != 0);
		CHECK(((ret ^ 0xd800) & -0x0800) != 0); // Surrogates
		*out++ = CAST16(ret);
		return true;
	}
	if ((first & 0x08) == 0)
	{
		ret = (first & 0x07) << 18;
		cont = MASK8(*in);
		CHECK(((cont ^ 0x80) & -0x40) == 0);
		ret |= (cont & 0x3f) << 12;
		CHECK(++in != end);
		cont = MASK8(*in);
		CHECK(((cont ^ 0x80) & -0x40) == 0);
		ret |= (cont & 0x3f) << 6;
		CHECK(++in != end);
		cont = MASK8(*in);
		CHECK(((cont ^ 0x80) & -0x40) == 0);
		ret |= cont & 0x3f;
		++in;
		CHECK(ret >= 0x10000);
		ret -= 0x10000;
		CHECK((ret & -0x100000) == 0); // Above U+10FFFF
		*out++ = CAST16(ret >> 10 | 0xd800);
		*out++ = CAST16(ret & 0x3ff | 0xdc00);
		return true;
	}
	if ((first & 0x04) == 0)
	{
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		CHECK(++in != end);
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		CHECK(++in != end);
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		CHECK(++in != end);
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		++in;
		return false;
	}
	if ((first & 0x02) == 0)
	{
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		CHECK(++in != end);
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		CHECK(++in != end);
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		CHECK(++in != end);
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		CHECK(++in != end);
		CHECK(((MASK8(*in) ^ 0x80) & -0x40) == 0);
		++in;
		return false;
	}
	return false;
}

// Internal function. Make sure that (in != end) before calling.
static bool NarrowChar(wstring::const_iterator & in, wstring::const_iterator end, back_insert_iterator<string> & out)
{
	uint32_t first = MASK16(*in++);
	if ((first & -0x0080) == 0)
	{
		CHECK(first != 0x0000); // NULL
		*out++ = CAST8(first);
		return true;
	}
	if ((first & -0x0800) == 0)
	{
		*out++ = CAST8(first >> 6 | -0x40);
		*out++ = CAST8(first & 0x3f | 0x80);
		return true;
	}
	if (((first ^ 0xd800) & -0x0800) != 0)
	{
		*out++ = CAST8(first >> 12 | -0x20);
		*out++ = CAST8(first >> 6 & 0x3f | 0x80);
		*out++ = CAST8(first & 0x3f | 0x80);
		return true;
	}
	else
	{
		CHECK((first & 0x0400) == 0);
		CHECK(in != end);
		uint32_t cont = MASK16(*in);
		CHECK(((cont ^ 0xdc00) & -0x0400) == 0);
		++in;
		uint32_t ret = ((first & 0x03ff) << 10 | cont & 0x03ff) + 0x10000;
		*out++ = CAST8(ret >> 18 | -0x10);
		*out++ = CAST8(ret >> 12 & 0x3f | 0x80);
		*out++ = CAST8(ret >> 6 & 0x3f | 0x80);
		*out++ = CAST8(ret & 0x3f | 0x80);
		return true;
	}
}

wstring Widen(const string s, bool nothrow)
{
	std::wstring r;
	auto in = s.cbegin();
	auto end = s.cend();
	auto out = back_inserter(r);
	while (in != end)
	{
		if (!WidenChar(in, end, out))
		{
			if (nothrow)
			{
				*out++ = CAST16(0xfffd);
			}
			else
			{
				throw runtime_error("Invalid UTF-8 string");
			}
		}
	}
	return r;
}

string Narrow(const wstring s, bool nothrow)
{
	std::string r;
	auto in = s.cbegin();
	auto end = s.cend();
	auto out = back_inserter(r);
	while (in != end)
	{
		if (!NarrowChar(in, end, out))
		{
			if (nothrow)
			{
				*out++ = '\xef';
				*out++ = '\xbf';
				*out++ = '\xbd';
			}
			else
			{
				throw runtime_error("Invalid UTF-16 string");
			}
		}
	}
	return r;
}


#endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32


int strcmpDiscardCaps(const char *str1, const char *str2)//strcmp which discards Caps
{
	if(str1==nullptr){
		return -1;
	}else if(str2==nullptr){
		return 1;
	}
    int result = 0 ;
    while (*str1 && *str2 && !result) 
    {
        result = static_cast<uint8_t>(*str1) - static_cast<uint8_t>(*str2);
		if(*str1>=65 && *str1<90) result+=32 ;
		if(*str2>=65 && *str2<90) result-=32 ;
        ++str1 ;
        ++str2 ;  
    }
	return result ;   
}
